package com.king.schedules;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.king.entity.MPost;
import com.king.service.MPostService;
import com.king.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
 * Seconds (秒) ：可以用数字0－59 表示；
 *
 * Minutes(分) ：可以用数字0－59 表示；
 *
 * Hours(时) ：可以用数字0-23表示；
 *
 * Day-of-Month(天) ：可以用数字1-31 中的任一一个值，但要注意一些特别的月份2月份没有只能1-28，有些月份没有31；
 *
 * Month(月) ：可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示；
 *
 * Day-of-Week(*每周*)*：*可以用数字1-7表示（1 ＝ 星期日）或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示；
 *
 * “/”：为特别单位，表示为“每”如“0/10”表示每隔10分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次，“3”表示从第3分钟开始执行；
 *
 * “?”：表示每月的某一天，或第周的某一天；
 *
 * “L”：用于每月，或每周，表示为每月的最后一天，或每个月的最后星期几如“6L”表示“每月的最后一个星期五”；
 *
 * “W”：表示为最近工作日，如“15W”放在每月（day-of-month）字段上表示为“到本月15日最近的工作日”；
 *
 * “#”：是用来指定“的”每月第n个工作日,例 在每周（day-of-week）这个字段中内容为”6#3” or “FRI#3” 则表示“每月第三个星期五”；
 *
 * “*” 代表整个时间段。
 */
@Component
@Slf4j
public class ViewCountSyncTask {

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    MPostService mPostService;

    //    @Scheduled(cron = "0/5 * * * * *")//每5秒同步一次
    @Scheduled(cron = "0 0/1 * * * *")//每1分钟同步一次
    public void task() {
        Map<Long, Integer> cachePostMap = new HashMap<>();//postId:viewCount
        Set<String> keys = redisUtil.keys("post:rank:*");
        keys.stream().forEach((key) -> {
            if (redisUtil.hHasKey(key, "post:viewCount")) {//1.获取需要同步的postId
                Long postId = Long.valueOf(key.substring("post:rank:".length()));
                Integer viewCount = (Integer) redisUtil.hget(key, "post:viewCount");
                cachePostMap.put(postId, viewCount);
            }
        });

        if (cachePostMap.isEmpty()) return;

        List<MPost> posts = mPostService.list(new QueryWrapper<MPost>().in("id", cachePostMap.keySet()));
        if (posts.isEmpty()) return;
        posts.stream().forEach((post) -> {
            post.setViewCount(cachePostMap.get(post.getId()));
        });

        boolean isUpdated = mPostService.updateBatchById(posts); //2.同步到数据库
        if (isUpdated) {
            posts.stream().forEach((post) -> {
                redisUtil.hdel("post:rank:" + post.getId(), "post:viewCount");//3.使缓存失效
                log.info("redis 同步成功！ --> {}",post.getId());
            });
        }
    }
}
